﻿using Microsoft.PointOfService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WellDone
{
    public partial class FormMain : Form
    {
        // System constants
        private const int WM_SYSCOMMAND = 0x0112;
        private const int SC_MINIMIZE = 0xf020;

        // Application constants
        private const int k_int_hidden = 0;
        private const int k_int_visible = 100;
        private const int k_int_max_retries = 5;
        private const int k_int_max_recs = 50;
        private const int k_int_exclusive_control = 1000;
        private const int k_int_sleep_time_in_ms = 1000;
        private const int k_int_status_closed = 5;
        private const int k_int_kitchen_print_width = 33;
        private const int k_int_kitchen_big_print_width = 16;
        private const int k_int_print_width = 48;
        private const int k_int_column_left_width = 38;
        private const int k_int_column_right_width = 10;
        private const int k_int_column_sales_amount_width = 6;
        private const int k_int_column_sales_total_amount_width = 8;
        private const int k_int_column_sales_width = 10;
        private const int k_int_column_sales_med_width = 7;
        private const int k_int_column_sales_small_width = 5;
        private const int k_int_column_sales_total_width = 20;
        private const int k_int_wide_column_left_width = 14;
        private const int k_int_option_width = 33;
        private const int k_int_kitchen_option_width = 18;
        private const string k_str_indent = "     ";
        private const string k_str_blank_price = "       ";
        private const string k_str_binding_configuration = "BasicHttpBinding_IServiceOpenRPOS";

        // Application data
        private bool bConnected = false;
        private int token = -1;
        private OpenRPOS.ServiceOpenRPOSClient svc;
        private OpenRPOS.Discount[] DiscountRecords;
        private OpenRPOS.MenuItem[] MenuItemRecords;
        private OpenRPOS.MenuCategory[] MenuCategoryRecords;
        private OpenRPOS.PrintQueue[] PrintQueueRecords;
        private OpenRPOS.OrderCheck[] OrderCheckRecords;
        private OpenRPOS.OrderSummary[] OrderSummaryRecords;
        private OpenRPOS.OrderDetail[] OrderDetailRecords;
        private OpenRPOS.OrderOption[] OrderOptionRecords;
        private OpenRPOS.Login[] LoginRecords;
        private OpenRPOS.Configuration[] ConfigurationRecords;
        private OpenRPOS.OpenItem[] OpenItemRecords;

        private PosPrinter m_Printer = null, m_KitchenPrinter = null;
        private static CashDrawer m_Drawer = null;

        private int iCurrMin = 0, iMaxRecs = k_int_max_recs;

        private float fTaxRate = 0;

        private static string strLastMessage = "";

        private static FormMain frmMain;

        public FormMain()
        {
            InitializeComponent();
        }

        private DateTime Now()
        {
            DateTime localTime = DateTime.Now;
            if (bConnected)
            {
                DateTime currentUTCTime = svc.GetCurrentTime(token);
                localTime = TimeZoneInfo.ConvertTime(currentUTCTime, TimeZoneInfo.Local);
            }
            return localTime;
        }

        private static void AppendToLog(string strMessage)
        {
            if (strMessage != strLastMessage)
            {
                string strLogFilename = Path.GetDirectoryName(Application.ExecutablePath) + "\\log.txt";
                // This text is added only once to the file. 
                if (!File.Exists(strLogFilename))
                {
                    // Create a file to write to. 
                    using (StreamWriter sw = File.CreateText(strLogFilename))
                    {
                        sw.WriteLine(frmMain.Now().ToShortDateString() + " " + frmMain.Now().ToShortTimeString() + ", " + strMessage);
                    }
                }
                else
                {
                    using (StreamWriter sw = File.AppendText(strLogFilename))
                    {
                        sw.WriteLine(frmMain.Now().ToShortDateString() + " " + frmMain.Now().ToShortTimeString() + "," + strMessage);
                    }
                }
                strLastMessage = strMessage;
            }
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_SYSCOMMAND)
            {
                if (m.WParam.ToInt32() == SC_MINIMIZE)
                {
                    this.Opacity = k_int_hidden;
                    return;
                }
            }
            base.WndProc(ref m);
        }
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Show the form when the user clicks "Open"
            this.Opacity = k_int_visible;
            this.BringToFront();
        }

        private void connectToWebService()
        {
            try
            {
                bConnected = false;
                svc = new OpenRPOS.ServiceOpenRPOSClient(k_str_binding_configuration, textBoxServiceAddress.Text);

                token = svc.Login(textBoxUsername.Text, textBoxPassword.Text);
                bConnected = (token > 0);
            }
            catch (Exception ex)
            {
                AppendToLog(ex.Message);
            }
        }

        private void initDevices()
        {
            buttonTestPrinter.Enabled = false;
            try
            {
                // Create PosExplorer
                PosExplorer posExplorer = new PosExplorer();
                DeviceInfo deviceInfo = null;
                if (checkBoxPrintReceipts.Checked)
                {
                    try
                    {
                        // Initialize the printer
                        deviceInfo = posExplorer.GetDevice(DeviceType.PosPrinter, textBoxLogicalPrinterName.Text.Trim());
                        m_Printer = (PosPrinter)posExplorer.CreateInstance(deviceInfo);

                        // Open the devices
                        m_Printer.Open();
                        m_Printer.Claim(k_int_exclusive_control);
                        m_Printer.DeviceEnabled = true;
                        // Output by the high quality mode
                        m_Printer.RecLetterQuality = true;

                        if (checkBoxUseCashDrawer.Checked)
                        {
                            // Initialize the cash drawer
                            deviceInfo = posExplorer.GetDevice(DeviceType.CashDrawer, textBoxLogicalCashDrawerName.Text.Trim());
                            m_Drawer = (CashDrawer)posExplorer.CreateInstance(deviceInfo);
                            // Prepare to use cash drawer
                            m_Drawer.Open();
                            m_Drawer.Claim(k_int_exclusive_control);
                            m_Drawer.DeviceEnabled = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        AppendToLog(ex.Message);
                        return;
                    }
                }
                // Setup the kitchen printer
                if ((textBoxKitchenPrinterName.Text.Trim() == "") || (textBoxKitchenPrinterName.Text.Trim() == textBoxLogicalPrinterName.Text.Trim()))
                {
                    m_KitchenPrinter = m_Printer;
                }
                else if (checkBoxPrintOrders.Checked == true) // Initialize the kitchen printer
                {
                    try
                    {
                        // Initialize the printer
                        deviceInfo = posExplorer.GetDevice(DeviceType.PosPrinter, textBoxKitchenPrinterName.Text.Trim());
                        m_KitchenPrinter = (PosPrinter)posExplorer.CreateInstance(deviceInfo);
                        // Open the devices
                        m_KitchenPrinter.Open();
                        // Get the exclusive control right for the opened devices
                        m_KitchenPrinter.Claim(k_int_exclusive_control);
                        // Enable the devices
                        m_KitchenPrinter.DeviceEnabled = true;
                        // Output by the high quality mode
                        m_KitchenPrinter.RecLetterQuality = true;
                    }
                    catch (Exception ex)
                    {
                        AppendToLog(ex.Message);
                        return;
                    }
                }

                // Load bitmap, if needed
                if (checkBoxPrintLogo.Checked && m_Printer.CapRecBitmap == true)
                {
                    bool bSetBitmapSuccess = false;
                    for (int iRetryCount = 0; iRetryCount < k_int_max_retries; iRetryCount++)
                    {
                        try
                        {
                            // Register a bitmap
                            m_Printer.SetBitmap(1, PrinterStation.Receipt,
                                textBoxLogoFileName.Text.Trim(), PosPrinter.PrinterBitmapAsIs,
                                PosPrinter.PrinterBitmapCenter);
                            bSetBitmapSuccess = true;
                            break;
                        }
                        catch (PosControlException pce)
                        {
                            if (pce.ErrorCode == ErrorCode.Failure && pce.ErrorCodeExtended == 0 && pce.Message == "It is not initialized.")
                            {
                                System.Threading.Thread.Sleep(k_int_sleep_time_in_ms);
                            }
                        }
                    }
                    if (!bSetBitmapSuccess)
                    {
                        AppendToLog("Failed to set bitmap.");
                    }
                }
            }
            catch (PosControlException ex)
            {
                AppendToLog(ex.Message);
            }
            // Initialization succeeded, enable the test print button
            buttonTestPrinter.Enabled = true;
        }

        protected override void OnLoad(EventArgs e)
        {
            // Hide the form initially
            this.Opacity = k_int_hidden;
            frmMain = this;
            AppendToLog("Starting...");
            // Load settings
            Properties.Settings.Default.Upgrade();
            textBoxServiceAddress.Text = Properties.Settings.Default.ServiceAddress.Trim();
            textBoxUsername.Text = Properties.Settings.Default.DefaultUsername.Trim();
            textBoxPassword.Text = Properties.Settings.Default.DefaultPassword.Trim();
            checkBoxPrintLogo.Checked = Properties.Settings.Default.PrintLogo;
            checkBoxPrintOrders.Checked = Properties.Settings.Default.PrintOrders;
            checkBoxPrintReceipts.Checked = Properties.Settings.Default.PrintReceipts;
            checkBoxUseCashDrawer.Checked = Properties.Settings.Default.UseCashDrawer;
            numericUpDownPrintRoute.Value = Properties.Settings.Default.PrintRoute;
            textBoxLogicalPrinterName.Text = Properties.Settings.Default.LogicalPrinterName.Trim();
            textBoxLogicalCashDrawerName.Text = Properties.Settings.Default.LogicalCashDrawerName.Trim();
            textBoxLogoFileName.Text = Properties.Settings.Default.LogoFilename.Trim();
            textBoxKitchenPrinterName.Text = Properties.Settings.Default.KitchenPrinterName;
            iCurrMin = Properties.Settings.Default.MinMenuItemID;
            iMaxRecs = Properties.Settings.Default.MaxRecs;
            // Initialize the devices (Printer/Cash Drawer)
            initDevices();
            // Attempt to connect to the web service
            if (textBoxServiceAddress.Text.Trim() != "")
                connectToWebService();
            // Display message if not logged in
            if (!bConnected)
                MessageBox.Show("Unable to login.  Please configure the web service.");
            else
            {
                // Load menu item data
                int iLastCount = -1;
                List<OpenRPOS.MenuItem> MenuItemRecordsList = new List<OpenRPOS.MenuItem>();
                while (MenuItemRecordsList.Count() > iLastCount)
                {
                    iLastCount = MenuItemRecordsList.Count();
                    OpenRPOS.MenuItem[] tmpMenuItemsArr = svc.GetMenuItemObjects(token, "Active=1 and ID between " + iCurrMin.ToString() + " and " + (iCurrMin + iMaxRecs).ToString());
                    foreach (OpenRPOS.MenuItem mi in tmpMenuItemsArr)
                        MenuItemRecordsList.Add(mi);
                    iCurrMin += iMaxRecs + 1;
                }
                MenuItemRecords = MenuItemRecordsList.ToArray();
                // Load menu category information
                MenuCategoryRecords = svc.GetMenuCategoryObjects(token, "Active=1");
                // Load configuration items...
                ConfigurationRecords = svc.GetConfigurationObjects(token, "1=1 order by ID");
                // Set the tax rate
                try
                {
                    OpenRPOS.Configuration cfg = ConfigurationRecords.Where(x => x.col_KeyName == "TaxRate").First();
                    if (cfg != null)
                        fTaxRate = (float)Convert.ToDouble(cfg.col_Value);
                }
                catch (Exception) { }
            }
            // Start the timer
            timerMain.Enabled = true;

            base.OnLoad(e);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Exit the application
            Application.Exit();
        }

        private void buttonTestService_Click(object sender, EventArgs e)
        {
            // Attempt to connect to the web service using current information
            connectToWebService();
            if (!bConnected)
                MessageBox.Show("Failed to connect to web service.");
            else
                MessageBox.Show("Successfully connected to web service.");
        }

        private void buttonBrowseFiles_Click(object sender, EventArgs e)
        {
            openFileDialogLogo.FileName = Path.GetFileName(textBoxLogoFileName.Text);
            openFileDialogLogo.InitialDirectory = Path.GetDirectoryName(textBoxLogoFileName.Text);
            // Allow the user to navigate to the location of the logo filename
            if (openFileDialogLogo.ShowDialog() == DialogResult.OK)
                textBoxLogoFileName.Text = openFileDialogLogo.FileName;
        }

        private void buttonTestPrinter_Click(object sender, EventArgs e)
        {
            // Print a test slip
            // Show the wait cursor and disable the "Test Drawer" button
            Cursor.Current = Cursors.WaitCursor;
            buttonTestPrinter.Enabled = false;
            // Initialization
            DateTime nowDate = Now();							//System date
            DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();	//Date Format
            dateFormat.MonthDayPattern = "MMMM";
            string strDate = nowDate.ToString("MMMM,dd,yyyy  HH:mm", dateFormat);

            try
            {
                //Batch processing mode
                m_Printer.TransactionPrint(PrinterStation.Receipt,
                    PrinterTransactionControl.Transaction);

                if (checkBoxPrintLogo.Checked)
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|1B");
                // Print address
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|N"
                    + "123xxstreet,xxxcity,xxxxstate\n");
                // Print phone number
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|rA"
                    + "TEL 9999-99-9999   C#2\n");
                // Print date
                //   \u001b|cA = Centering char
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + strDate + "\n\n");
                // Print buying goods
                m_Printer.PrintNormal(PrinterStation.Receipt, "apples                  $20.00\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "grapes                  $30.00\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "bananas                 $40.00\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "lemons                  $50.00\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "oranges                 $60.00\n\n");
                // Print the total cost
                // \u001b|bC = Bold
                // \u001b|uC = Underline
                // \u001b|2C = Wide charcter
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|bC"
                    + "Tax excluded.          $200.00" + "\u001b|N\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|uC"
                    + "Tax  5.0%               $10.00" + "\u001b|N\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|bC" + "\u001b|2C"
                    + "Total   $210.00" + "\u001b|N\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "Customer's payment     $250.00\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "Change                  $40.00\n\n");
                // Feed the receipt to the cutter position automatically, and cut.
                //   \u001b|#fP = Line Feed and Paper cut	
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|fP");

                m_Printer.TransactionPrint(PrinterStation.Receipt, PrinterTransactionControl.Normal);
            }
            catch (PosControlException ex)
            {
                AppendToLog(ex.Message);
            }
            // Re-enable the print button
            buttonTestPrinter.Enabled = true;
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Free resources...
            if (m_Printer != null)
            {
                try
                {
                    // Cancel the device
                    m_Printer.DeviceEnabled = false;
                    // Release the device exclusive control right
                    m_Printer.Release();
                }
                catch (PosControlException)
                {
                }
                finally
                {
                    // Finish using the device.
                    m_Printer.Close();
                }
            }
            // Free kitchen printer...
            if (m_KitchenPrinter != null)
            {
                try
                {
                    // Cancel the device
                    m_KitchenPrinter.DeviceEnabled = false;
                    // Release the device exclusive control right
                    m_KitchenPrinter.Release();
                }
                catch (PosControlException)
                {
                }
                finally
                {
                    // Finish using the device.
                    m_KitchenPrinter.Close();
                }
            }
            // Free the cash drawer...
            if (m_Drawer != null)
            {
                try
                {
                    // Cancel the device
                    m_Drawer.DeviceEnabled = false;
                    // Release the device exclusive control right.
                    m_Drawer.Release();
                }
                catch (PosControlException)
                {
                }
                finally
                {
                    // Finish using the device.
                    m_Drawer.Close();
                }
            }

        }

        private static void openCashDrawer()
        {
            try
            {
                // Open the drawer by using the "OpenDrawer" method
                m_Drawer.OpenDrawer();
                // Wait during opend drawer.
                while (m_Drawer.DrawerOpened == false)
                {
                    System.Threading.Thread.Sleep(100);
                }
                // When the drawer is not closed in ten seconds after opening, beep until it is closed.
                // If  that method is executed, the value is not returned until the drawer is closed.
                m_Drawer.WaitForDrawerClose(10000, 2000, 100, 1000);
                Cursor.Current = Cursors.Default;
            }
            catch (PosControlException)
            {
                AppendToLog("An error occurred when opening the cash drawer.");
            }
        }
        private void buttonTestCashDrawer_Click(object sender, EventArgs e)
        {
            // Show the wait cursor and disable the "Test Drawer" button
            Cursor.Current = Cursors.WaitCursor;
            buttonTestCashDrawer.Enabled = false;
            // Open the cash drawer...
            openCashDrawer();
            // Re-enable the button
            buttonTestCashDrawer.Enabled = true;
        }

        private void buttonUpdateConfiguration_Click(object sender, EventArgs e)
        {
            // Save changes to the config file
            Properties.Settings.Default.ServiceAddress = textBoxServiceAddress.Text.Trim();
            Properties.Settings.Default.DefaultUsername = textBoxUsername.Text.Trim();
            Properties.Settings.Default.DefaultPassword = textBoxPassword.Text.Trim();
            Properties.Settings.Default.PrintLogo = checkBoxPrintLogo.Checked;
            Properties.Settings.Default.PrintOrders = checkBoxPrintOrders.Checked;
            Properties.Settings.Default.PrintReceipts = checkBoxPrintReceipts.Checked;
            Properties.Settings.Default.UseCashDrawer = checkBoxUseCashDrawer.Checked;
            Properties.Settings.Default.PrintRoute = (ushort)numericUpDownPrintRoute.Value;
            Properties.Settings.Default.LogicalPrinterName = textBoxLogicalPrinterName.Text.Trim();
            Properties.Settings.Default.LogicalCashDrawerName = textBoxLogicalCashDrawerName.Text.Trim();
            Properties.Settings.Default.KitchenPrinterName = textBoxKitchenPrinterName.Text.Trim();
            Properties.Settings.Default.LogoFilename = textBoxLogoFileName.Text.Trim();
            Properties.Settings.Default.Save();
            // Display message
            MessageBox.Show("Configuration information has been saved.  You must re-start the program to re-initialize devices if logical names or logo changes were made.");
        }
        private void printOrder(OpenRPOS.PrintQueue pq)
        {
            string strLine;
            int iPrintRoute = (int)numericUpDownPrintRoute.Value;
            bool bHeaderPrinted = false;
            // Print chit...
            try
            {
                // Get the order information
                OrderSummaryRecords = svc.GetOrderSummaryObjects(token, "ID=" + pq.col_OrderSummaryID.ToString());
                LoginRecords = svc.GetLoginObjects(token, "ID=" + OrderSummaryRecords[0].col_LoginID);
                OrderDetailRecords = svc.GetOrderDetailObjects(token, "isnull(sent,0)=0 and OrderSummaryID=" + pq.col_OrderSummaryID.ToString());
                if (OrderDetailRecords.Count() > 0)
                {
                    // Load options...
                    string strOrderDetailIDs = "(";
                    foreach (OpenRPOS.OrderDetail od in OrderDetailRecords)
                    {
                        strOrderDetailIDs += od.col_ID.ToString() + ",";
                    }
                    strOrderDetailIDs = strOrderDetailIDs.Substring(0, strOrderDetailIDs.Length - 1) + ")";
                    OrderOptionRecords = svc.GetOrderOptionObjects(token, "OrderDetailID in " + strOrderDetailIDs + " order by ID");
                    bool bLastDetailRecord, bLastOption;
                    List<int> splitItemList = new List<int>();
                    // Print order details...
                    foreach (OpenRPOS.OrderDetail od in OrderDetailRecords)
                    {
                        // Determine if this is a special instruction for printing...
                        OpenRPOS.MenuItem mi = new OpenRPOS.MenuItem();
                        OpenRPOS.MenuCategory mc = new OpenRPOS.MenuCategory();
                        if (od.col_OpenItemID > 0)
                        {
                            OpenItemRecords = svc.GetOpenItemObjects(token, "ID=" + od.col_OpenItemID);
                        }
                        else
                        {
                            mi = MenuItemRecords.Where(x => x.col_ID == od.col_MenuItemID).First();
                            mc = MenuCategoryRecords.Where(x => x.col_ID == mi.col_MenuCategoryID).First();
                        }
                        // Only print order items routed to this printer
                        if ((mc.col_PrintRoute == iPrintRoute) || (od.col_OpenItemID > 0))
                        {
                            // Flag the record as being printed
                            od.bFilterSent = true;
                            od.col_Sent = true;
                            svc.UpdateOrderDetailObject(token, od);

                            if (!bHeaderPrinted)
                            {
                                // Batch processing mode
                                //m_Printer.TransactionPrint(PrinterStation.Receipt, PrinterTransactionControl.Transaction);
                                // Print current date/time
                                //   \u001b|cA = Centering char
                                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\n\n\n\n\n\u001b|cA" + Now().ToString() + "\n");
                                if (OrderSummaryRecords[0].col_CarryOut == true)
                                {
                                    m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2CCarry Out\n");
                                    m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2C" + OrderSummaryRecords[0].col_CustomerName + "\n");
                                }
                                else
                                {
                                    // Print table #
                                    m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2CTable #" + OrderSummaryRecords[0].col_TableNumber.ToString() + "\n");
                                }
                                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|cAServer: " + LoginRecords[0].col_DisplayName.ToString() + "\n");
                                m_KitchenPrinter.PrintImmediate(PrinterStation.Receipt, "\n");
                                bHeaderPrinted = true;
                            }
                            // Don't print split items more than once...
                            if (od.col_SplitItemID > 0)
                            {
                                if (splitItemList.Contains(od.col_SplitItemID))
                                    continue;
                                else
                                    splitItemList.Add(od.col_SplitItemID);
                            }

                            // Check for special instructions...
                            if (od.col_OpenItemID > 0)
                            {
                                strLine = OpenItemRecords.First().col_Name.PadRight(k_int_kitchen_big_print_width);
                                m_KitchenPrinter.PrintImmediate(PrinterStation.Receipt, "\u001b|bC\u001b|2C" + strLine + "\n");
                                strLine = OpenItemRecords.First().col_Description;
                                m_KitchenPrinter.PrintImmediate(PrinterStation.Receipt, k_str_indent + strLine + "\n");
                            }
                            else
                            {
                                strLine = mi.col_FullName.PadRight(k_int_kitchen_big_print_width);
                                m_KitchenPrinter.PrintImmediate(PrinterStation.Receipt, "\u001b|bC\u001b|2C" + strLine + "\n");
                            }
                            bLastDetailRecord = (od == OrderDetailRecords.Last());
                            // Print options...
                            OpenRPOS.MenuItem miOption = mi;
                            foreach (OpenRPOS.OrderOption oo in OrderOptionRecords.Where(x => x.col_OrderDetailID == od.col_ID))
                            {
                                mi = MenuItemRecords.Where(x => x.col_ID == oo.col_MenuItemID).First();
                                strLine = "";
                                if (oo.col_Price > mi.col_Price)
                                    strLine = "Double ";
                                else
                                    strLine = (oo.col_Exclude ? "No " : (!mi.col_Pizza && miOption.col_Pizza) ? "Add " : "");
                                strLine += mi.col_FullName.PadRight(k_int_kitchen_option_width + k_int_column_right_width);
                                bLastOption = (oo == OrderOptionRecords.Last());
                                // Remove text in parenthesis
                                strLine = Regex.Replace(strLine, "(\\(.*\\))", "").Trim();
                                if (strLine.Length > 0)
                                    m_KitchenPrinter.PrintImmediate(PrinterStation.Receipt, k_str_indent + strLine + "\n");
                            }
                            m_KitchenPrinter.PrintImmediate(PrinterStation.Receipt, "\n");
                        }
                    }
                    if (bHeaderPrinted)
                    {
                        // Feed the receipt to the cutter position automatically, and cut.
                        m_KitchenPrinter.PrintImmediate(PrinterStation.Receipt, "\n\n");
                        m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|fP");
                    }
                }
            }
            catch (PosControlException ex)
            {
                AppendToLog(ex.Message);
            }
            // Mark as "Printed"
            pq.bFilterPrinted = true;
            pq.col_Printed = true;
            svc.UpdatePrintQueueObject(token, pq);
        }
        private void printReceipt(OpenRPOS.PrintQueue pq)
        {
            string strLine, strDiscLine = "";
            decimal dRunningTotal = 0, dDiscountAmount;
            // Print receipt...
            try
            {
                // Open the cash drawer if flagged to do so...
                if (pq.col_OpenCashDrawer && checkBoxUseCashDrawer.Checked)
                {
                    Thread t = new Thread(new ThreadStart(openCashDrawer));
                    t.Start();
                }

                // Print logo header, if that option is selected
                if (checkBoxPrintLogo.Checked)
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|1B");
                // Print current date/time
                //   \u001b|cA = Centering char
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + Now().ToString() + "\n");
                // Print header objects
                foreach (OpenRPOS.Configuration cfg in ConfigurationRecords)
                {
                    if (cfg.col_KeyName == "ReceiptHeader")
                        m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + cfg.col_Value + "\n");
                }
                // Get the check information
                OrderCheckRecords = svc.GetOrderCheckObjects(token, "ID=" + pq.col_OrderCheckID.ToString());
                OrderSummaryRecords = svc.GetOrderSummaryObjects(token, "ID=" + OrderCheckRecords.First().col_OrderSummaryID.ToString());
                LoginRecords = svc.GetLoginObjects(token, "ID=" + OrderSummaryRecords[0].col_LoginID.ToString());
                if (!OrderSummaryRecords.First().col_SplitEvenly)
                {
                    if (OrderSummaryRecords.First().col_Split <= 1)
                        OrderDetailRecords = svc.GetOrderDetailObjects(token, "OrderSummaryID=" + OrderCheckRecords.First().col_OrderSummaryID.ToString() + " and SeatNumber in (0,1)");
                    else
                        OrderDetailRecords = svc.GetOrderDetailObjects(token, "OrderSummaryID=" + OrderCheckRecords.First().col_OrderSummaryID.ToString() + " and SeatNumber=" +
                            OrderCheckRecords.First().col_SeatNumber.ToString());
                }
                else
                    OrderDetailRecords = svc.GetOrderDetailObjects(token, "OrderSummaryID=" + OrderCheckRecords.First().col_OrderSummaryID.ToString());
                if (OrderSummaryRecords[0].col_CarryOut == true)
                {
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2CCarry Out\n");
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2C" + OrderSummaryRecords[0].col_CustomerName.Trim() + "\n");
                }
                else
                {
                    // Print Check #
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2CCheck #" + OrderCheckRecords.First().col_ID.ToString() + "\n");
                    // Print table #
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2CTable #" + OrderSummaryRecords[0].col_TableNumber.ToString() + "\n");
                }
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cAServer: " + LoginRecords[0].col_DisplayName.ToString() + "\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "\n");

                // Load options...
                if (OrderDetailRecords.Count() > 0)
                {
                    string strOrderDetailIDs = "(";
                    foreach (OpenRPOS.OrderDetail od in OrderDetailRecords)
                    {
                        strOrderDetailIDs += od.col_ID.ToString() + ",";
                    }
                    strOrderDetailIDs = strOrderDetailIDs.Substring(0, strOrderDetailIDs.Length - 1) + ")";
                    OrderOptionRecords = svc.GetOrderOptionObjects(token, "OrderDetailID in " + strOrderDetailIDs + " order by ID");
                }
                else OrderOptionRecords = null;
                bool bLastDetailRecord, bLastOption;
                // Print order details...
                foreach (OpenRPOS.OrderDetail od in OrderDetailRecords)
                {
                    OpenRPOS.MenuItem mi = new OpenRPOS.MenuItem();
                    decimal dItemPrice;
                    if (OrderSummaryRecords.First().col_SplitEvenly)
                        dItemPrice = od.col_Price / OrderSummaryRecords.First().col_Split;
                    else
                        dItemPrice = od.col_Price;

                    string strPrefix = "";
                    if (od.col_SplitItemID > 0)
                    {
                        OpenRPOS.SplitItem[] SplitItemRecords = svc.GetSplitItemObjects(token, "ID=" + od.col_SplitItemID.ToString());
                        if (SplitItemRecords.Count() > 0)
                        {
                            strPrefix = "1/" + SplitItemRecords[0].col_Split + " ";
                        }
                    }

                    // Add option prices to total...
                    foreach (OpenRPOS.OrderOption oo in OrderOptionRecords.Where(x => x.col_OrderDetailID == od.col_ID))
                    {
                        if (OrderSummaryRecords.First().col_SplitEvenly)
                            dItemPrice += oo.col_Price / OrderSummaryRecords.First().col_Split;
                        else
                            dItemPrice += oo.col_Price;
                    }

                    dRunningTotal += dItemPrice;
                    if (od.col_OpenItemID > 0)
                    {
                        OpenItemRecords = svc.GetOpenItemObjects(token, "ID=" + od.col_OpenItemID.ToString());
                        strPrefix = strPrefix + OpenItemRecords.First().col_Name;
                        strLine = strPrefix.PadRight(k_int_column_left_width) + (" $" + dItemPrice.ToString("N")).PadLeft(k_int_column_right_width);
                    }
                    else
                    {
                        mi = MenuItemRecords.Where(x => x.col_ID == od.col_MenuItemID).First();
                        strPrefix = strPrefix + mi.col_FullName;
                        strLine = strPrefix.PadRight(k_int_column_left_width) + (" $" + dItemPrice.ToString("N")).PadLeft(k_int_column_right_width);
                    }
                    bLastDetailRecord = (od == OrderDetailRecords.Last());

                    // Determine if an item has been discounted.  If so, display it...
                    DiscountRecords = svc.GetDiscountObjects(token, "ID=" + od.col_DiscountID.ToString());
                    dDiscountAmount = 0;
                    if (DiscountRecords.Count() > 0)
                    {
                        strDiscLine = "  ***Discount";
                        if (DiscountRecords[0].col_IsPercent == true)
                        {
                            strDiscLine += " - " + DiscountRecords[0].col_Amount.ToString("N") + "%";
                            dDiscountAmount = dItemPrice * (DiscountRecords[0].col_Amount / 100);
                        }
                        else
                            dDiscountAmount = DiscountRecords[0].col_Amount;
                    }

                    if (bLastDetailRecord && (OrderOptionRecords.Where(x => x.col_OrderDetailID == od.col_ID).Count() == 0) && (dDiscountAmount == 0))
                        m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|uC" + strLine + "\u001b|N\n");
                    else
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine);
                    // Print options...
                    OpenRPOS.MenuItem miOption = mi;
                    foreach (OpenRPOS.OrderOption oo in OrderOptionRecords.Where(x => x.col_OrderDetailID == od.col_ID))
                    {
                        mi = MenuItemRecords.Where(x => x.col_ID == oo.col_MenuItemID).First();
                        strLine = "";
                        if (oo.col_Price > mi.col_Price)
                            strLine = "Double ";
                        else
                            strLine = (oo.col_Exclude ? "No " : (!mi.col_Pizza && miOption.col_Pizza) ? "Add " : "");
                        strLine = (strLine + mi.col_FullName).PadRight(k_int_option_width) + k_str_indent.PadLeft(k_int_column_right_width);
                        // Remove text in parenthesis
                        strLine = Regex.Replace(strLine, "(\\(.*\\))", "");
                        strLine = k_str_indent + strLine + k_str_blank_price;
                        if (strLine.Length > k_int_print_width)
                            strLine = strLine.Substring(0, k_int_print_width);
                        bLastOption = (oo == OrderOptionRecords.Last());
                        if (bLastDetailRecord && bLastOption && (dDiscountAmount == 0))
                            m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|uC" + strLine + "\u001b|N\n");
                        else if (strLine.Trim().Length > 0)
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\n");
                    }
                    if (dDiscountAmount > 0)
                    {
                        strLine = strDiscLine.PadRight(k_int_column_left_width) + ("($" + dDiscountAmount.ToString("N")).PadLeft(k_int_column_right_width - 1) + ")";
                        if (bLastDetailRecord)
                            m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|uC" + strLine + "\u001b|N\n");
                        else
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine);
                        dRunningTotal -= dDiscountAmount;
                    }

                }
                // Determine if there are any discounts that need to be applied
                DiscountRecords = svc.GetDiscountObjects(token, "ID=" + OrderSummaryRecords.First().col_DiscountID.ToString());

                dDiscountAmount = 0;
                strLine = "";
                if (DiscountRecords.Count() > 0)
                {
                    strLine = "Discount";
                    if (DiscountRecords[0].col_IsPercent == true)
                    {
                        strLine += " - " + DiscountRecords[0].col_Amount.ToString("N") + "%";
                        dDiscountAmount = dRunningTotal * (DiscountRecords[0].col_Amount / 100);
                    }
                    else
                        dDiscountAmount = DiscountRecords[0].col_Amount;
                }
                if (dDiscountAmount > 0)
                {
                    string strSubtotalLine = "Subtotal".PadRight(k_int_column_left_width) + ("$" + dRunningTotal.ToString("N")).PadLeft(k_int_column_right_width) + "\n";
                    m_Printer.PrintNormal(PrinterStation.Receipt, strSubtotalLine);
                    strLine = strLine.PadRight(k_int_column_left_width) + ("($" + dDiscountAmount.ToString("N")).PadLeft(k_int_column_right_width - 1) + ")\n";
                    m_Printer.PrintNormal(PrinterStation.Receipt, strLine);
                    // Print the new subtotal
                    strLine = "New Subtotal".PadRight(k_int_column_left_width) + ("$" + OrderCheckRecords.First().col_Subtotal.ToString("N")).PadLeft(k_int_column_right_width) + "\n";
                    m_Printer.PrintNormal(PrinterStation.Receipt, strLine);
                }
                else
                {
                    strLine = "Subtotal".PadRight(k_int_column_left_width) + ("$" + OrderCheckRecords.First().col_Subtotal.ToString("N")).PadLeft(k_int_column_right_width) + "\n";
                    m_Printer.PrintNormal(PrinterStation.Receipt, strLine);
                }
                // Print the tax and total
                strLine = "Tax".PadRight(k_int_column_left_width) + ("$" + OrderCheckRecords.First().col_Tax.ToString("N")).PadLeft(k_int_column_right_width) + "\n";
                m_Printer.PrintNormal(PrinterStation.Receipt, strLine);
                decimal dTotal = OrderCheckRecords.First().col_Tax + OrderCheckRecords.First().col_Subtotal;
                strLine = "Total".PadRight(k_int_wide_column_left_width) + ("$" + dTotal.ToString("N")).PadLeft(k_int_column_right_width);
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|bC" + "\u001b|2C" + strLine + "\u001b|N\n");
                if (OrderCheckRecords.First().col_AmountTendered > 0)
                {
                    strLine = "Amt. Tendered".PadRight(k_int_wide_column_left_width) + ("$" + (OrderCheckRecords.First().col_AmountTendered).ToString("N")).PadLeft(k_int_column_right_width);
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|bC" + "\u001b|2C" + strLine + "\u001b|N\n");
                    strLine = "Change".PadRight(k_int_wide_column_left_width) + ("$" + (OrderCheckRecords.First().col_AmountTendered - dTotal).ToString("N")).PadLeft(k_int_column_right_width);
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|bC" + "\u001b|2C" + strLine + "\u001b|N\n");
                }

                // Print footer objects
                m_Printer.PrintNormal(PrinterStation.Receipt, "\n\n");

                foreach (OpenRPOS.Configuration cfg in ConfigurationRecords)
                {
                    if (cfg.col_KeyName == "ReceiptFooter")
                        m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + cfg.col_Value + "\n");
                }

                // Feed the receipt to the cutter position automatically, and cut.
                m_Printer.PrintNormal(PrinterStation.Receipt, "\n\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|fP");
            }
            catch (PosControlException ex)
            {
                AppendToLog(ex.Message);
            }
            // Mark as "Printed"
            pq.bFilterPrinted = true;
            pq.col_Printed = true;
            svc.UpdatePrintQueueObject(token, pq);
        }

        private void printCreditSlip(OpenRPOS.PrintQueue pq)
        {
            string strLine;
            // Print receipt...
            try
            {
                // Open the cash drawer if flagged to do so...
                if (pq.col_OpenCashDrawer && checkBoxUseCashDrawer.Checked)
                {
                    Thread t = new Thread(new ThreadStart(openCashDrawer));
                    t.Start();
                }
                // Print logo header, if that option is selected
                if (checkBoxPrintLogo.Checked)
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|1B");
                // Print current date/time
                //   \u001b|cA = Centering char
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + Now().ToString() + "\n");
                // Print header objects
                foreach (OpenRPOS.Configuration cfg in ConfigurationRecords)
                {
                    if (cfg.col_KeyName == "ReceiptHeader")
                        m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + cfg.col_Value + "\n");
                }
                // Get the check information
                OrderCheckRecords = svc.GetOrderCheckObjects(token, "ID=" + pq.col_OrderCheckID);
                // Print Check #
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA\u001b|bC\u001b|2CCheck #" + pq.col_OrderCheckID.ToString() + "\n");
                strLine = "Amount".PadRight(k_int_wide_column_left_width) + ("$" + (OrderCheckRecords.First().col_Tax + OrderCheckRecords.First().col_Subtotal).ToString("N")).PadLeft(k_int_column_right_width);
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|bC" + "\u001b|2C" + strLine + "\u001b|N\n");
                m_Printer.PrintImmediate(PrinterStation.Receipt, "\n\nTip:____________________________________________");
                m_Printer.PrintImmediate(PrinterStation.Receipt, "\n\nTotal:__________________________________________");
                m_Printer.PrintImmediate(PrinterStation.Receipt, "\n\nX_______________________________________________");
                m_Printer.PrintImmediate(PrinterStation.Receipt, "I agree to pay the above total amount according ");
                m_Printer.PrintImmediate(PrinterStation.Receipt, "to the card issuer's agreement.                 ");
                // Feed the receipt to the cutter position automatically, and cut.
                m_Printer.PrintImmediate(PrinterStation.Receipt, "\n\n");
                m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|fP");
            }
            catch (PosControlException ex)
            {
                AppendToLog(ex.Message);
            }
            // Mark as "Printed"
            pq.bFilterPrinted = true;
            pq.col_Printed = true;
            svc.UpdatePrintQueueObject(token, pq);
        }

        private void printSalesReport(OpenRPOS.PrintQueue pq)
        {
            string strLine;
            // Print sales report...
            try
            {
                // Pull back order summary records for user...
                // Retrieve order summary records for closed checks on selected date
                string strFilter = "Status=" + k_int_status_closed.ToString() +
                    " and TimeOpened between '" + Now().Date.Date.ToString() + "' and '" + Now().Date.Date.AddDays(1).ToString() + "'";
                OrderSummaryRecords = svc.GetOrderSummaryObjects(token, strFilter);
                // Get corresponding checks...
                if (OrderSummaryRecords.Count() > 0)
                {
                    // Batch processing mode
                    m_Printer.TransactionPrint(PrinterStation.Receipt, PrinterTransactionControl.Transaction);

                    // Print current date/time
                    //   \u001b|cA = Centering char
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + Now().ToString() + "\n");
                    // Print header objects
                    foreach (OpenRPOS.Configuration cfg in ConfigurationRecords)
                    {
                        if (cfg.col_KeyName == "ReceiptHeader")
                            m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + cfg.col_Value + "\n");
                    }
                    // Get a list of employees that correspond to the closed check records
                    List<int> loginIDList = new List<int>();
                    string strOrderSummaryIDs = "";
                    decimal dCashTotal, dCreditTotal, dOtherTotal, dCreditTipTotal, dOtherTipTotal, dStoreCashTotal = 0, dTaxTotal = 0,
                        dStoreTaxTotal = 0, dStoreCreditTotal = 0, dStoreCreditTipTotal = 0, dStoreOtherTotal = 0, dStoreOtherTipTotal = 0;
                    foreach (OpenRPOS.OrderSummary os in OrderSummaryRecords)
                    {
                        strOrderSummaryIDs += os.col_ID.ToString() + ",";
                        if (!loginIDList.Contains(os.col_LoginID))
                            loginIDList.Add(os.col_LoginID);
                    }
                    strOrderSummaryIDs = strOrderSummaryIDs.Substring(0, strOrderSummaryIDs.Length - 1);
                    // Get closed checks...
                    OrderCheckRecords = svc.GetOrderCheckObjects(token,"OrderSummaryID in (" +
                        strOrderSummaryIDs + ")  and IsNull(Paid,0)=1 order by OrderSummaryID, ID");
                    string strLoginIDs = "";
                    foreach (int loginID in loginIDList)
                        strLoginIDs += loginID.ToString() + ",";
                    strLoginIDs = strLoginIDs.Substring(0, strLoginIDs.Length - 1);
                    // Get employees associated with selected summary records
                    LoginRecords = svc.GetLoginObjects(token, "ID in (" + strLoginIDs + ") order by DisplayName");
                    // Print data...
                    foreach (OpenRPOS.Login login in LoginRecords)
                    {
                        if ((login.col_ID == pq.col_LoginID) || (pq.col_LoginID == 0))
                        {
                            dCashTotal = 0;
                            dCreditTotal = 0;
                            dCreditTipTotal = 0;
                            dOtherTotal = 0;
                            dOtherTipTotal = 0;
                            dTaxTotal = 0;
                            // Print user's display name
                            strLine = login.col_DisplayName;
                            m_Printer.PrintNormal(PrinterStation.Receipt, "\n\u001b|bC" + "\u001b|2C" + strLine + "\u001b|N\n");
                            // Print header...
                            strLine = "Check".PadRight(k_int_column_sales_med_width) + "Tbl".PadRight(k_int_column_sales_small_width) +
                                " Time".PadRight(k_int_column_sales_width) + "  Total".PadRight(k_int_column_sales_width) + 
                                "    Tips".PadRight(k_int_column_sales_width) + " Pmt";
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            // Print out a list of checks for current user
                            foreach (OpenRPOS.OrderCheck oc in OrderCheckRecords)
                            {
                                OpenRPOS.OrderSummary os = OrderSummaryRecords.Where(x => x.col_ID == oc.col_OrderSummaryID).First();
                                if (login.col_ID == os.col_LoginID)
                                {
                                    strLine = oc.col_ID.ToString().PadRight(k_int_column_sales_med_width) + (
                                        (os.col_CarryOut)?("ToGo".PadRight(k_int_column_sales_small_width)):
                                        (" "+os.col_TableNumber.ToString()).PadRight(k_int_column_sales_small_width)) +
                                        (os.col_TimeSent.ToShortTimeString()+"  ").PadLeft(k_int_column_sales_width) +
                                        "$" + (oc.col_Subtotal + oc.col_Tax).ToString("N").PadLeft(k_int_column_sales_amount_width) +
                                        "    $" + oc.col_Gratuity.ToString("N").PadLeft(k_int_column_sales_amount_width) + (oc.col_PaymentType == 0 ? "  Cash" : 
                                        (oc.col_PaymentType == 1 ? "  Credit": "   Other"));
                                    m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                                    if (oc.col_PaymentType == 0)
                                        dCashTotal += oc.col_Subtotal + oc.col_Tax;
                                    else if (oc.col_PaymentType == 1)
                                    {
                                        dCreditTotal += oc.col_Subtotal + oc.col_Tax;
                                        dCreditTipTotal += oc.col_Gratuity;
                                    }
                                    else
                                    {
                                        dOtherTotal += oc.col_Subtotal + oc.col_Tax;
                                        dOtherTipTotal += oc.col_Gratuity;
                                    }
                                    dTaxTotal += oc.col_Tax;
                                }
                            }
                            dStoreCashTotal += dCashTotal;
                            dStoreCreditTotal += dCreditTotal;
                            dStoreCreditTipTotal += dCreditTipTotal;
                            dStoreOtherTotal += dOtherTotal;
                            dStoreOtherTipTotal += dOtherTipTotal;
                            dStoreTaxTotal += dTaxTotal;
                            // Print user totals...
                            m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|N\n");
                            strLine = "Total Sales w/Tax".PadRight(k_int_column_sales_total_width) + "$" + (dCashTotal + dCreditTotal + dOtherTotal).ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            strLine = "Total Tax".PadRight(k_int_column_sales_total_width) + "$" + dTaxTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            strLine = "Total Cash Sales".PadRight(k_int_column_sales_total_width) + "$" + dCashTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            strLine = "Total Credit Sales".PadRight(k_int_column_sales_total_width) + "$" + dCreditTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            strLine = "Total Other Sales".PadRight(k_int_column_sales_total_width) + "$" + dOtherTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            strLine = "Total Credit Tips".PadRight(k_int_column_sales_total_width) + "$" + dCreditTipTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            strLine = "Total Other Tips".PadRight(k_int_column_sales_total_width) + "$" + dOtherTipTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                            strLine = "Cash Due".PadRight(k_int_column_sales_total_width) + "$" + (dCashTotal - dCreditTipTotal - dOtherTipTotal).ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                            m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n\n");
                        }
                    }
                    // Print store totals if "All" was selected...
                    if (pq.col_LoginID == 0)
                    {
                        strLine = "Store Totals";
                        m_Printer.PrintNormal(PrinterStation.Receipt, "\n\u001b|bC" + "\u001b|2C" + strLine + "\u001b|N\n");
                        strLine = "Total Sales w/Tax".PadRight(k_int_column_sales_total_width) + "$" + (dStoreCashTotal + dStoreCreditTotal + dStoreOtherTotal).ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                        strLine = "Total Tax".PadRight(k_int_column_sales_total_width) + "$" + dStoreTaxTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                        strLine = "Total Cash Sales".PadRight(k_int_column_sales_total_width) + "$" + dStoreCashTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                        strLine = "Total Credit Sales".PadRight(k_int_column_sales_total_width) + "$" + dStoreCreditTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                        strLine = "Total Other Sales".PadRight(k_int_column_sales_total_width) + "$" + dStoreOtherTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                        strLine = "Total Credit Tips".PadRight(k_int_column_sales_total_width) + "$" + dStoreCreditTipTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                        strLine = "Total Other Tips".PadRight(k_int_column_sales_total_width) + "$" + dStoreOtherTipTotal.ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n");
                        strLine = "Cash Due".PadRight(k_int_column_sales_total_width) + "$" + (dStoreCashTotal - dStoreCreditTipTotal - dStoreOtherTipTotal).ToString("N").PadLeft(k_int_column_sales_total_amount_width);
                        m_Printer.PrintNormal(PrinterStation.Receipt, strLine + "\u001b|N\n\n");
                    }
                    // Feed the receipt to the cutter position automatically, and cut.
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\n\n");
                    m_Printer.PrintNormal(PrinterStation.Receipt, "\u001b|fP");

                    m_Printer.TransactionPrint(PrinterStation.Receipt, PrinterTransactionControl.Normal);
                }
            }
            catch (PosControlException ex)
            {
                AppendToLog(ex.Message);
            }
            // Mark as "Printed"
            pq.bFilterPrinted = true;
            pq.col_Printed = true;
            svc.UpdatePrintQueueObject(token, pq);
        }

        private void timerMain_Tick(object sender, EventArgs e)
        {
            OpenRPOS.PrintQueue currentPQ = null;

            // If the service is connected, check the print queue
            if (bConnected)
            {
                try
                {
                    currentPQ = null;
                    PrintQueueRecords = svc.GetPrintQueueObjects(token, "Printed=0 and PrintRoute=" + numericUpDownPrintRoute.Value.ToString());
                    // Iterate over the returned records
                    foreach (OpenRPOS.PrintQueue pq in PrintQueueRecords)
                    {
                        if (!pq.col_Printed)
                        {
                            currentPQ = pq;
                            // Check to see if the drawer needs to be opened...
                            if (pq.col_OpenCashDrawer && checkBoxUseCashDrawer.Checked)
                            {
                                // Mark as "Printed"
                                pq.bFilterPrinted = true;
                                pq.col_Printed = true;
                                svc.UpdatePrintQueueObject(token, pq);
                                // Open the drawer...
                                Thread t = new Thread(new ThreadStart(openCashDrawer));
                                t.Start();
                            }
                            // Print receipt after payment...
                            if (pq.col_PrintReceipt && checkBoxPrintReceipts.Checked)
                                printReceipt(pq);
                            // Print credit slip...
                            else if (pq.col_CreditSlip && checkBoxPrintReceipts.Checked)
                                printCreditSlip(pq);
                            // Print sales report...
                            else if (pq.col_PrintSales && checkBoxPrintReceipts.Checked)
                                printSalesReport(pq);
                            // Print the order...
                            else if (pq.col_PrintOrder && checkBoxPrintOrders.Checked)
                                printOrder(pq);
                        }
                        else
                            currentPQ = null;
                    }
                }
                catch (Exception ex)
                {
                    timerMain.Enabled = false;
                    AppendToLog(ex.Message);
                    bConnected = false;
                    if (currentPQ != null)
                    {
                        // Mark as "Printed"
                        currentPQ.bFilterPrinted = true;
                        currentPQ.col_Printed = true;
                        try
                        {
                            svc.UpdatePrintQueueObject(token, currentPQ);
                        }
                        catch (Exception except)
                        {
                            AppendToLog("timerMain_Tick() - calling svc.UpdatePrintQueueObject - " + except.Message);
                        }
                    }
                    timerMain.Enabled = true;
                }
            }
            else
                connectToWebService();
        }

        private void buttonTestKitchenPrinter_Click(object sender, EventArgs e)
        {
            // Print a test slip
            // Show the wait cursor and disable the "Test Drawer" button
            Cursor.Current = Cursors.WaitCursor;
            buttonTestKitchenPrinter.Enabled = false;
            // Initialization
            DateTime nowDate = Now();							//System date
            DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();	//Date Format
            dateFormat.MonthDayPattern = "MMMM";
            string strDate = nowDate.ToString("MMMM,dd,yyyy  HH:mm", dateFormat);

            try
            {
                // Batch processing mode
                m_Printer.TransactionPrint(PrinterStation.Receipt, PrinterTransactionControl.Transaction);

                // Print address
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|N"
                    + "123xxstreet,xxxcity,xxxxstate\n");
                // Print phone number
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|rA"
                    + "TEL 9999-99-9999   C#2\n");
                // Print date
                //   \u001b|cA = Centering char
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|cA" + strDate + "\n\n");
                // Print buying goods
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "apples                  $20.00\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "grapes                  $30.00\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "bananas                 $40.00\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "lemons                  $50.00\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "oranges                 $60.00\n\n");
                // Print the total cost
                // \u001b|bC = Bold
                // \u001b|uC = Underline
                // \u001b|2C = Wide charcter
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|bC"
                    + "Tax excluded.          $200.00" + "\u001b|N\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|uC"
                    + "Tax  5.0%               $10.00" + "\u001b|N\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|bC" + "\u001b|2C"
                    + "Total   $210.00" + "\u001b|N\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "Customer's payment     $250.00\n");
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "Change                  $40.00\n\n");
                // Feed the receipt to the cutter position automatically, and cut.
                //   \u001b|#fP = Line Feed and Paper cut	
                m_KitchenPrinter.PrintNormal(PrinterStation.Receipt, "\u001b|fP");

                m_Printer.TransactionPrint(PrinterStation.Receipt, PrinterTransactionControl.Normal);
            }
            catch (PosControlException ex)
            {
                AppendToLog(ex.Message);
            }
            // Re-enable the print button
            buttonTestKitchenPrinter.Enabled = true;
        }

        private void contextMenuStripMain_Opening(object sender, CancelEventArgs e)
        {

        }

    }
}
